﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;

namespace InductBase.Extensions
{
    public static class Rec2Ext
    {
        static public Rec ToRec(this RectangleF recF)
        {
            return Rec.FromRectangleF(recF);
        }

        static public Rec ToRec(this Rectangle rec)
        {
            return Rec.FromRectangle(rec);
        }
    }

    public static class Vec2Ext
    {
        static public PointF ToPointF(this Vec2 vec)
        {
            return new PointF((float)vec.X, (float)vec.Y);
        }
        static public SizeF ToSizeF(this Vec2 vec)
        {
            return new SizeF((float)vec.X, (float)vec.Y);
        }

        static public Point ToPoint(this Vec2 vec)
        {
            return new Point((int)vec.X, (int)vec.Y);
        }
        static public Size ToSize(this Vec2 vec)
        {
            return new Size((int)vec.X, (int)vec.Y);
        }

        static public Vec2 ToVec2(this PointF point)
        {
            return new Vec2(point.X, point.Y);
        }

        static public Vec2 ToVec2(this Point point)
        {
            return new Vec2(point.X, point.Y);
        }

        static public Vec2 ToVec2(this SizeF size)
        {
            return new Vec2(size.Width, size.Height);
        }

        static public Vec2 ToVec2(this Size size)
        {
            return new Vec2(size.Width, size.Height);
        }

        //=================Vec2i

        static public PointF ToPointF(this Vec2i vec)
        {
            return new PointF((float)vec.X, (float)vec.Y);
        }
        static public SizeF ToSizeF(this Vec2i vec)
        {
            return new SizeF((float)vec.X, (float)vec.Y);
        }

        static public Point ToPoint(this Vec2i vec)
        {
            return new Point((int)vec.X, (int)vec.Y);
        }
        static public Size ToSize(this Vec2i vec)
        {
            return new Size((int)vec.X, (int)vec.Y);
        }

        static public Vec2i ToVec2i(this PointF point)
        {
            return new Vec2i((int)point.X, (int)point.Y);
        }

        static public Vec2i ToVec2i(this Point point)
        {
            return new Vec2i(point.X, point.Y);
        }

        static public Vec2i ToVec2i(this SizeF size)
        {
            return new Vec2i((int)size.Width, (int)size.Height);
        }

        static public Vec2i ToVec2i(this Size size)
        {
            return new Vec2i(size.Width, size.Height);
        }
    }

    public static class GraphicsExt
    {
        static public void DrawImage(this Graphics g, Image image, Rectangle destRect, Rectangle srcRect, Color color, ImageLayout imageLayout = ImageLayout.Stretch)
        {
            g.DrawImage(image, (RectangleF)destRect, (RectangleF)srcRect, color, imageLayout);
        }

        static public void DrawImage(this Graphics g, Image image, Rectangle destRect, Color color, ImageLayout imageLayout = ImageLayout.Stretch)
        {
            g.DrawImage(image, (RectangleF)destRect, new RectangleF(0, 0, image.Width, image.Height), color, imageLayout);
        }

        static public void DrawImage(this Graphics g, Image image, RectangleF destRect, RectangleF srcRect, Color color, ImageLayout imageLayout = ImageLayout.Stretch)
        {
            if (imageLayout == ImageLayout.Tile)
            {
                g.DrawImageTiled(image, Rectangle.Ceiling(destRect), color);
                return;
            }

            var state = g.Save();
            //if (imageLayout == ImageLayout.Tile)
            //{
            //    throw new ArgumentException("Not supported", "imageLayout");
            //}

            double toFlt = 1.0 / 255.0;

            float fR = (float)(color.R * toFlt);
            float fG = (float)(color.G * toFlt);
            float fB = (float)(color.B * toFlt);
            float fA = (float)(color.A * toFlt);

            ColorMatrix colorMatrix =
               new ColorMatrix(
                new[]{
            new[]{fR, 0.0f, 0.0f, 0.0f, 0.0f},
            new[]{0.0f, fG, 0.0f, 0.0f, 0.0f},
            new[]{0.0f, 0.0f, fB, 0.0f, 0.0f},
            new[]{0.0f, 0.0f, 0.0f, fA, 0.0f},
            new[]{0.0f, 0.0f, 0.0f, 0.0f, 1.0f}
                   });

            ImageAttributes imageAttributes = new ImageAttributes();

            imageAttributes.SetColorMatrix(
               colorMatrix,
               ColorMatrixFlag.Default,
               ColorAdjustType.Bitmap);

            switch (imageLayout)
            {
                case ImageLayout.Stretch:
                    break;
                case ImageLayout.Zoom:
                    destRect = srcRect.ToRec().ZoomedIn(destRect.ToRec()).ToRectangleF();
                    break;
                case ImageLayout.Center:
                    var tmp = srcRect.ToRec();
                    tmp.Center = destRect.ToRec().Center;
                    destRect = tmp.ToRectangleF();
                    break;
                case ImageLayout.None:
                    destRect = new RectangleF(destRect.Location, srcRect.Size);
                    break;
            }

            g.DrawImage(image, Rectangle.Ceiling(destRect), srcRect.X, srcRect.Y, srcRect.Width, srcRect.Height, GraphicsUnit.Pixel, imageAttributes);
            g.Restore(state);
        }

        static public void DrawImageBorders(this Graphics g, Image pattern, Rectangle destRect, int margins, Color color)
        {
            Vec2 margin = new Vec2(margins, margins);
            Rec area = destRect.ToRec();
            Vec2 src_size = pattern.Size.ToVec2();
            double marg_x = margin.X;
            double marg_y = margin.Y;

            Rec src_tl = Rec.FromLocationSize(Vec2.Null, margin);
            Rec dst_tl = Rec.FromLocationSize(area.Location, margin);

            Rec src_tr = Rec.FromLocationSize(new Vec2(src_size.X - marg_x, 0), margin);
            Rec dst_tr = Rec.FromLocationSize(area.Location + new Vec2(area.Size.X - marg_x, 0), margin);

            Rec src_bl = Rec.FromLocationSize(new Vec2(0, src_size.Y - marg_y), margin);
            Rec dst_bl = Rec.FromLocationSize(area.Location + new Vec2(0, area.Size.Y - marg_y), margin);

            Rec src_br = Rec.FromLocationSize(new Vec2(src_size.X - marg_x, src_size.Y - marg_y), margin);
            Rec dst_br = Rec.FromLocationSize(area.Location + new Vec2(area.Size.X - marg_x, area.Size.Y - marg_y), margin);

            g.DrawImage(pattern, dst_tl, src_tl, color);
            g.DrawImage(pattern, dst_tr, src_tr, color);
            g.DrawImage(pattern, dst_bl, src_bl, color);
            g.DrawImage(pattern, dst_br, src_br, color);

            Rec src_ml = new Rec(0, marg_y, marg_x, src_size.Y - 2 * marg_y);
            Rec dst_ml = new Rec(0, marg_y, marg_x, area.Size.Y - 2 * marg_y);
            dst_ml.Location += area.Location;
            g.DrawImage(pattern, dst_ml, src_ml, color);

            Rec src_mr = new Rec(src_size.X - marg_x, marg_y, marg_x, src_size.Y - 2 * marg_y);
            Rec dst_mr = new Rec(area.Size.X - marg_x, marg_y, marg_x, area.Size.Y - 2 * marg_y);
            dst_mr.Location += area.Location;
            g.DrawImage(pattern, dst_mr, src_mr, color);

            Rec src_mm = Rec.FromLocationSize(margin, src_size - 2 * margin);
            Rec dst_mm = Rec.FromLocationSize(margin, area.Size - 2 * margin);
            dst_mm.Location += area.Location;
            g.DrawImage(pattern, dst_mm, src_mm, color);

            Rec src_tm = new Rec(marg_x, 0, src_size.X - 2 * marg_x, marg_y);
            Rec dst_tm = new Rec(marg_x, 0, area.Size.X - 2 * marg_x, marg_y);
            dst_tm.Location += area.Location;
            g.DrawImage(pattern, dst_tm, src_tm, color);

            Rec src_bm = new Rec(marg_x, src_size.Y - marg_y, src_size.X - 2 * marg_x, marg_y);
            Rec dst_bm = new Rec(marg_x, area.Size.Y - marg_y, area.Size.X - 2 * marg_x, marg_y);
            dst_bm.Location += area.Location;
            g.DrawImage(pattern, dst_bm, src_bm, color);
        }

        static public void DrawImageTiled(this Graphics g, Image pattern, Rectangle area, Color color)
        {
            g.DrawImageTiled(pattern, area, color, new Point(0, 0));
        }

        static public void DrawImageTiled(this Graphics g, Image pattern, Rectangle area, Color color, Point shift)
        {
            Vec2 _shift = shift.ToVec2();
            Vec2 patternSize = pattern.Size.ToVec2();
            Rec _area = area.ToRec();
            _shift = _shift % patternSize;

            for (int i = -1; i < _area.Width / patternSize.X + 2; i++)
                for (int j = -1; j < _area.Height / patternSize.Y + 2; j++)
                {
                    Vec2 pos = new Vec2(i * patternSize.X, j * patternSize.Y) + _shift;
                    Vec2 size = patternSize;
                    Vec2 blitpos = Vec2.Null;

                    if (pos.X < 0)
                    {
                        blitpos.X = -pos.X;
                        size.X = size.X - blitpos.X;
                        pos.X = 0;
                    }

                    if (pos.Y < 0)
                    {
                        blitpos.Y = -pos.Y;
                        size.Y = size.Y - blitpos.Y;
                        pos.Y = 0;
                    }

                    if (pos.X + size.X > _area.Width)
                    {
                        size.X = _area.Width - pos.X;
                    }

                    if (pos.Y + size.Y > _area.Height)
                    {
                        size.Y = _area.Height - pos.Y;
                    }

                    Vec2 position = _area.Location + pos;

                    Rec blit = Rec.FromLocationSize(blitpos, size);

                    //g.DrawImage(pattern, trans.Position, blit, color);
                    g.DrawImage(pattern, Rec.FromLocationSize(position, size).ToRectangle(), blit.ToRectangle(), color);
                }
        }
    }
}
